using System;
using System.Collections.Generic;

using Pegasus.Diagnostics;

namespace Pegasus.Runtime.Serialization.Formatters
{
	/// <summary>
	/// This class is used to track object type for system formatters.
	/// </summary>
	internal class FormatterTypeManager : IEnumerable< KeyValuePair<long, Type> >
	{
		// Local Instance Values
		private long m_typeIndex = 1;
		private Dictionary<long, Type> m_typeTable = new Dictionary<long, Type>();

		/// <summary>
		/// Initializes a new instance of the <see cref="T:FormatterTypeManager"/> class.
		/// </summary>
		public FormatterTypeManager()
		{
		}

		/// <summary>
		/// Gets the type.
		/// </summary>
		/// <param name="typeId">The type id.</param>
		/// <returns></returns>
		public Type GetType( long typeId )
		{
			if( m_typeTable.ContainsKey( typeId ) )
			{
				return m_typeTable[ typeId ];
			}

			return null;
		}

		/// <summary>
		/// Gets the type id.
		/// </summary>
		/// <param name="type">The type.</param>
		/// <returns></returns>
		public long GetTypeId( Type type )
		{
			if( m_typeTable.ContainsValue( type ) )
			{
				foreach( KeyValuePair<long, Type> entry in m_typeTable )
				{
					if( type.Equals( entry.Value ) )
					{
						return entry.Key;
					}
				}
			}
			else
			{
				long typeId = m_typeIndex;
				m_typeIndex++;

				m_typeTable.Add( typeId, type );

				return typeId;
			}

			throw new Exception( "Table contains value but could not locate the key." );
		}

		/// <summary>
		/// Registers the type.
		/// </summary>
		/// <param name="type">The type.</param>
		/// <param name="typeId">The type id.</param>
		public void RegisterType( Type type, long typeId )
		{
			// Check parameters
			ParamCode.AssertNotNull( type, "type" );
			ParamCode.AssertRange( typeId, 1, long.MaxValue, "typeId" );

			if( m_typeTable.ContainsKey( typeId ) )
			{
				throw new ArgumentException( "There is an type already registered with the given id" );
			}

			// Move the type index byond the new type id value.
			if( m_typeIndex <= typeId )
			{
				m_typeIndex = typeId + 1;
			}

			m_typeTable.Add( typeId, type );
		}

		/// <summary>
		/// Resets this instance.
		/// </summary>
		public void Reset()
		{
			m_typeIndex = 1;
			m_typeTable.Clear();
		}

		/// <summary>
		/// Returns an enumerator that iterates through the collection.
		/// </summary>
		/// <returns>
		/// A <see cref="T:System.Collections.Generic.IEnumerator`1"></see> that can be used to iterate through the collection.
		/// </returns>
		public IEnumerator<KeyValuePair<long, Type>> GetEnumerator()
		{
			return m_typeTable.GetEnumerator();
		}

		/// <summary>
		/// Returns an enumerator that iterates through a collection.
		/// </summary>
		/// <returns>
		/// An <see cref="T:System.Collections.IEnumerator"></see> object that can be used to iterate through the collection.
		/// </returns>
		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
		{
			return m_typeTable.GetEnumerator();
		}
	}
}
